/**
	@file IOExtraction.h

		Deals with extraction from I/O

	@author Tony Huynh
	@date Created: May 2009 \n
		  Updated: Sept. 2009
 */
#ifndef IOEXTRACTION_H_
#define IOEXTRACTION_H_

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>

////////////////////////////////
// FUNCTION DECLARATIONS
////////////////////////////////

// Extracts a value from the input stream and puts it in a variable
template<typename T>
bool IOExtract(std::istream& in, const std::vector<char>& leftSkipTokens, T& variable, const std::vector<char>& delimiters);

// Auxiliary Function used by IOExtract()
// checks if there's a match between c (char) and the tokens inside the vector
static bool operator==(const char c, const std::vector<char>& tokens);

// Returns the contents of a file in the format of a string
std::string readFile(const std::string& filename);

////////////////////////////////
// FUNCTION DEFINITIONS
////////////////////////////////

/**
	@brief Extracts a value from the input stream and puts it in a variable

	@param in the input stream
	@param leftSkipTokens the characters on the left of the content to be extracted to be skipped
	@param variable this will contain the extracted content
	@param delimiters the delimiting character; it is not extracted from the input stream.
	@return bool, true if variable is assigned (i.e. - the result is nonempty)
 */
template<typename T>
bool IOExtract(std::istream& in, const std::vector<char>& leftSkipTokens, T& variable, const std::vector<char>& delimiters)
{
	// skip all leftSkipTokens
	while (in.peek() == leftSkipTokens)
	{
		in.get();
	}

	// read until delimiter
	std::string result;
	while (!(in.peek() == delimiters) && !in.eof())
	{
		result += (char)in.get();
	}

	// put result in variable
	if (result.size() != 0)
	{
		std::istringstream istr(result);
		istr >> variable;
		return true;
	}

	// no result
	return false;
}

/**
	@brief Checks if there's a match between c (char) and the tokens inside the vector

	@param c the character to be checked for inside the vector
	@param tokens the tokens to be checked with the character
	@return bool, true if there's a match; otherwise, false.
 */
static bool operator==(const char c, const std::vector<char>& tokens)
{
	for (unsigned int i = 0; i < tokens.size(); ++i)
	{
		if (c == tokens[i])
			return true;
	}

	return false;
}

/**
	@brief Returns the contents of a file in the format of a string

	@param filename the name of the file to be read
	@return string, the content of the file
 */
std::string readFile(const std::string& filename)
{
	// open the variable file
	std::ifstream fin(filename.c_str());
	if (!fin.is_open())
	{
		std::cerr << "Error: Cannot Open " + filename + " File" << std::endl;
		fin.close();
		return "";
	}
	else
	{

		// read the file
		const int BUFFER_SIZE = 2048;
		char tempBuffer[BUFFER_SIZE];
		std::string result = "";
		int amount_read = 0;
		while (fin.good())
		{
			fin.read(tempBuffer, BUFFER_SIZE);
			amount_read = fin.gcount();
			result.append(tempBuffer, amount_read);
		}

		// close the file
		fin.close();

		return result;
	}
}

#endif	// IOEXTRACTION_H_
